----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    02:17:18 10/01/2009 
-- Design Name: 
-- Module Name:    program_rx - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;


---- Uncomment the following library declaration if instantiating
---- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;

entity program_rx is
  port ( clk      : in  std_logic;
         reset    : in  std_logic;
         data_out : out std_logic_vector (127 downto 0);
         has_data : out std_logic;
         rd_ack   : in  std_logic;
         rd_uart  : out std_logic;
         rx_empty : in  std_logic;
         r_data   : in  std_logic_vector (7 downto 0);
         leds     : out std_logic_vector (7 downto 0));
end program_rx;


architecture arch of program_rx is
  signal led_bus : std_logic_vector(7 downto 0);

  signal checksum                        : integer range 0 to 128;
  signal packet                          : std_logic_vector (175 downto 0);
  type statetype is ( S0, s01,          -- shift byte from uart onto packet
                      S1,  --S11, S12, S13, s14,  --validate packet
                      s2, s21, s90);    -- wait for data to be read
  signal state, next_state, return_state : statetype                       := S0;
  signal shortcounter                    : std_logic_vector (24 downto 0 ) := (others => '0');
begin

  leds(6 downto 0) <= led_bus(6 downto 0);
  leds(7)          <= rx_empty;

  state    <= next_state;
  data_out <= packet ( 159 downto 32 );

  process (clk, reset) is
  begin
    if (reset = '1') then
      packet     <= (others => '0');
-- packet structure (for my own benefit)
-- 175 downto 168 -> header
-- 167 downto 144 -> reserved
-- 143 downto 16 -> data
-- 15 downto 8 -> checksum
-- 7 downto 0 -> footer
      next_state <= S0;
      checksum   <= 0;
      has_data   <= '0';
      rd_uart    <= '0';
    elsif( rising_edge(clk) ) then
      case state is

        -- Read and shift if there is data available
        -- also pack some checksum stuff into
        -- these cycles
        when S0 =>
          led_bus        <= x"FF";
          if (rx_empty = '0') then
            rd_uart      <= '1';
            next_state <= S01;
            --return_state <= S01;
            --next_state   <= S90;
            -- subtract the checksum of the byte that is about
            -- to get pushed off the data section

            checksum   <= checksum - (CONV_INTEGER(packet(143)) +
                                      CONV_INTEGER(packet(142)) +
                                      CONV_INTEGER(packet(141)) +
                                      CONV_INTEGER(packet(140)) +
                                      CONV_INTEGER(packet(139)) +
                                      CONV_INTEGER(packet(138)) +
                                      CONV_INTEGER(packet(137)) +
                                      CONV_INTEGER(packet(136)));
          else
            next_state <= S0;
          end if;

        when S01 =>
          led_bus    <= x"01";
          packet     <= r_data & packet(175 downto 8);
          checksum   <= checksum + (CONV_INTEGER(r_data(7)) +
                                    CONV_INTEGER(r_data(6)) +
                                    CONV_INTEGER(r_data(5)) +
                                    CONV_INTEGER(r_data(4)) +
                                    CONV_INTEGER(r_data(3)) +
                                    CONV_INTEGER(r_data(2)) +
                                    CONV_INTEGER(r_data(1)) +
                                    CONV_INTEGER(r_data(0)));
          rd_uart    <= '0';
          next_state <= S1;


          ---------------------------------
          -- Packet Validation
        when S1 =>
          led_bus      <= x"10";
          if ((packet(7 downto 0) = x"00") and
              (packet(31 downto 8) = x"000000") and
              --(checksum = CONV_INTEGER(packet(167 downto 160))) and
              (packet(175 downto 168) = x"FF")) then
            next_state <= S2;           -- valid
          else
            next_state <= S0;
            --next_state <= S2;
          end if;

          ---------------------------------
          -- wait for implementor to take data

        when S2 =>
          led_bus      <= x"20";
          if (rd_ack = '1') then
            next_state <= S2;
          else
            has_data   <= '1';
            next_state <= S21;
          end if;

        when S21 =>
          led_bus      <= x"21";
          if (rd_ack = '1') then
            next_state <= S0;
            has_data   <= '0';
          else
            next_state <= S21;
          end if;

        when S90 =>
          if(shortcounter = "1011111010111100001000000") then
            shortcounter <= "0000000000000000000000000";
            next_state   <= return_state;
          else
            shortcounter <= shortcounter + 1;
            next_state   <= S90;
          end if;


      end case;
    end if;
  end process;
  

end arch;

